<?php
/**
 * Classe abstraite servant au entityBean
 * @author Gaétan Collaud
 */
abstract class AbstractEntity{
	/**
	 * Liste des types de données supporté
	 */
	const TYPE_INT = 1;
	const TYPE_STRING = 2;
	const TYPE_BOOLEAN = 3;

	/**
	 * @var Array<String, int> Liste des champs avec leur type
	 */
	private static $fields = array();
	/**
	 * @var Array<String> Liste des clés primaires
	 */
	private static $pk = array();
	/**
	 * @var String champ autoincrémenté (null si aucun)
	 */
	private static $autoIncr;
	/**
	 * @var String nom de la table
	 */
	private static $table_name;

	/**
	 * Redéfinit le type de tout les champs
	 * @param String $table_name le nom de la table
	 */
	public function __construct($table_name){
		self::$table_name = $table_name;
		
		foreach($this as $k=>$v){
			if(isset(self::$fields[$k])){
				switch (self::$fields[$k]){
					case self::TYPE_INT:
						$this->$k = (int)$v;
					break;
					case self::TYPE_BOOLEAN:
						if($v=='true') $this->$k = true;
						else if($v=='false') $this->$k = false;
						else $this->$k = (bool)$v;
					break; 
				}
			}else
				Log::warn(__METHOD__, "Attribut <b>$k</b> de la table <b>$table_name</b> non définit dans l'entity beans");
		}
	}

	/**
	 * Ajoute un champ
	 * @param String $name Le nom du champ
	 * @param int $type Le type du champs (voir les constantes)
	 */
	protected static function addField($name, $type){
		self::$fields[$name] = $type;
	}

	/**
	 * Ajoute une clé primaire
	 * @param String $name le nom du champ
	 */
	protected static function addPk($name){
		self::$pk[] = $name;
	}

	/**
	 * Ajoute une clé primaire auto incrémentée
	 * @param String $name le nom du champ
	 */
	protected static function addAutoPK($name){
		self::$pk[] = $name;
		self::$autoIncr = $name;
	}

	/**
	 * Crée la requête d'insertion de l'objet
	 * @return String la requête SQL
	 */
	public function insert(){
		$first = true;
		$key = "";
		$value= "";
		foreach(self::$fields as $k=>$type){
			if($k!=self::$autoIncr){
				if(!$first){ $key .= ", "; $value .= ", "; }
				$first = false;
				$key .= $k;
				$value .= $this->escape($this->$k, $type);
			}
		}
		return "INSERT INTO ".self::$table_name." ($key) VALUES ($value);\n";
	}

	/**
	 * Crée la requête de mise à jour
	 * @param array<String, String> $where les conditions à remplir sous forme champs=valeur
	 * @return String la requête SQL
	 */
	public function update(array $where = null){
		//field
		$first = true;
		$f = "";
		foreach(self::$fields as $k=>$type){
			if(!in_array($k, self::$pk)){
				if(!$first) $f .= ", ";
				$first = false;
				$f .= $k.'='.$this->escape($this->$k, $type);
			}
		}

		//pk
		if(is_null($where)){
			foreach(self::$pk as $pk){
				$where[$pk] = $this->$pk;
			}
		}

		//where
		$w = "";
		$first = true;
		foreach($where as $k=>$v){
			if(!$first) $f .= " AND ";
			$first = false;
			$w = $k.'='.$this->escape($v, @self::$fields[$k]);
		}
		return "UPDATE ".self::$table_name." SET $f WHERE $w;";
	}

	/**
	 * Crée la requête de suppression
	 * @param array<String, String> $where les conditions à remplir sous forme champs=valeur
	 * @return String la requête SQL
	 */
	public function delete(array $where = null){

		//pk
		if(is_null($where)){
			foreach(self::$pk as $pk){
				$where[$pk] = $this->$pk;
			}
		}

		//where
		$w = "";
		$first = true;
		foreach($where as $k=>$v){
			if(!$first) $f .= " AND ";
			$first = false;
			$w = $k.'='.$this->escape($v, @self::$fields[$k]);
		}
		return "DELETE FROM ".self::$table_name." WHERE $w;";
	}

	/**
	 * Echape et ajoute les guillemets au besoin pour une valeur
	 * @param String $v la valeur
	 * @param int $type le type (voir constante)
	 * @return String le champ échapé
	 */
	private function escape($v, $type){
		switch ($type){
			case self::TYPE_BOOLEAN:
				if(Base::getSql()->isBoolSupport()) return $v ? 'true' : 'false';
				else return (int)$v;
			break;
			case self::TYPE_INT:
				return (int)$v;
			break;
			default:
				return '"'.Base::getSql()->escape($v).'"';
		}
	}
}
?>
